using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace UIDCToolsProfiler
{
    public class UIDCTreeNode
    {
        public bool isCanvas = false;
        public int batchCount = 0;
        public int maskBatchCount = 0;
        private static float nodeDefaultMarginX = 12f;
        private static float nodeDefaultWidth = 100f;

        private static float nodeDefaultWidthObject = 200f;
        private static float nodeDefaultHeight = 15;
        private static int BatchIDWidth = 100;
        private static float toggleWidth = 50;
        private static float noFadeSpace = 14;
        public static List<int> BatchesList = new List<int>();
        private bool isShow = true;
        private bool isDestroy = false;
        private bool isRoot = false;
        public bool IsRoot
        {
            set
            {
                isRoot = value;
            }
            get
            {
                return isRoot;
            }
        }

        private int depth = 0;
        public int Depth
        {
            set
            {
                depth = value;
            }
            get
            {
                return depth;
            }
        }

        private string title = null;
        private string subTitle = null;
        private RectTransform rectTransform = null;
        private GUIStyle subTitleGuiStyle = null;
        private UIDCTreeNode parent = null;
        private GameObject assetObject = null;
        public GameObject AssetObject
        {
            get
            {
                return assetObject;
            }
        }
        private List<UIDCTreeNode> children = new List<UIDCTreeNode>();
        private Rect position = new Rect(0, 0, nodeDefaultWidth, nodeDefaultHeight);
        private float marginX = nodeDefaultMarginX;
        private Vector2 recursiveSize = new Vector2(nodeDefaultWidth, nodeDefaultHeight);
        private UINodeInfo nodeInfo;


        public UIDCTreeNode(string title, GameObject assetObject = null, int depth = 0)
        {
            this.title = title;
            this.assetObject = assetObject;
            this.depth = depth;

            GenInfo();

            if (title == null)
            {
                position.width = nodeDefaultWidthObject;
            }
        }

     
        public void OnGUI()
        {
            Texture _GUIStyle = null;

            if (nodeInfo.BatchID >= 0)
            {
                int index = BatchesList.IndexOf(nodeInfo.BatchID);
                _GUIStyle = UIDCTools.GetStyles(index, BatchesList.Count);
            }
            bool toggle = false;
            if (children.Count > 0)
            {
                EditorGUILayout.BeginHorizontal();
                if (_GUIStyle != null)
                {
                    toggle = GUILayout.Button(_GUIStyle, EditorStyles.helpBox, GUILayout.Width(toggleWidth), GUILayout.Height(16));
                }
                else
                {
                    toggle = GUILayout.Button(UIDCTools.GetEmptyTexture(), EditorStyles.helpBox, GUILayout.Width(toggleWidth), GUILayout.Height(16));
                }
                if (nodeInfo.BatchID >=0)
                {
                    string value = nodeInfo.BatchID.ToString();
                    if(isCanvas)
                    {
                        value += "(Canvas)";
                    }
                    EditorGUILayout.LabelField(value, GUILayout.Width(BatchIDWidth));
                }else
                {
                    EditorGUILayout.LabelField("    ", GUILayout.Width(BatchIDWidth));
                }

                GUILayout.Space(position.x);
                isShow = EditorGUILayout.Foldout(isShow, title, true);

                EditorGUILayout.EndHorizontal();
                if (isShow)
                {
                    float childY = position.y + position.height;
                    for (int i = 0; i < children.Count; i++)
                    {
                        if (children[i] != null)
                        {
                            children[i].position.y = childY;
                            children[i].OnGUI();
                            childY = childY + children[i].recursiveSize.y;
                        }
                    }
                }
            }
            else
            {
                EditorGUILayout.BeginHorizontal();
                if (_GUIStyle != null)
                {
                    toggle = GUILayout.Button(_GUIStyle, EditorStyles.helpBox, GUILayout.Width(toggleWidth), GUILayout.Height(16));
                }
                else
                {
                    toggle = GUILayout.Button(UIDCTools.GetEmptyTexture(), EditorStyles.helpBox, GUILayout.Width(toggleWidth), GUILayout.Height(16));
                }
                if (nodeInfo.BatchID >= 0)
                {
                    EditorGUILayout.LabelField(nodeInfo.BatchID.ToString(), GUILayout.Width(BatchIDWidth));
                    GUILayout.Space(position.x + noFadeSpace);
                }
                else
                {
                    EditorGUILayout.LabelField("", GUILayout.Width(BatchIDWidth));
                    GUILayout.Space(position.x + noFadeSpace);
                }
               
                EditorGUILayout.LabelField(title);
                EditorGUILayout.EndHorizontal();
            }
            if (toggle)
            {
                Selection.activeGameObject = assetObject;
            }
            CalcRecursiveSize();
        }

        public UIDCTreeNode Clone()
        {
            UIDCTreeNode cloneNode = new UIDCTreeNode(title, assetObject, depth);
            cloneNode.SetSubTitle(subTitle, subTitleGuiStyle != null ? subTitleGuiStyle.normal.textColor : Color.green);
            cloneNode.SetParent(parent);
            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    cloneNode.AddChild(children[i].Clone());
                }
            }

            return cloneNode;
        }

        public void Destroy()
        {
            SetParent(null);
            assetObject = null;
            isDestroy = true;

            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    children[i].Destroy();
                }
            }
            children.Clear();
        }

        public void PrintNodeInfo()
        {
            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    children[i].PrintNodeInfo();
                }
            }
        }

        public void UpdataInfo()
        {
            nodeInfo.RefreshInfo();
            if (nodeInfo.Use)
            {
                string name = nodeInfo.Name;
                if (nodeInfo.check > -1)
                {
                    title = string.Format("{0}  | Depth:{1} | MatID:{2} | TexID:{3} | InMask:{4} | InMask2D:{5} | HierarychyOrder:{6} | check : {7} )",
                        name, nodeInfo.Depth, nodeInfo.MaterialInstanceID, nodeInfo.TextureID, nodeInfo.IsInMask, nodeInfo.IsInMask2D, nodeInfo.HierarychyOrder, nodeInfo.check);
                }
                else
                {
                    title = string.Format("{0}  | Depth:{1} | MatID:{2} | TexID:{3} | InMask:{4} | InMask2D:{5} | HierarychyOrder:{6} ",
                        name, nodeInfo.Depth, nodeInfo.MaterialInstanceID, nodeInfo.TextureID, nodeInfo.IsInMask, nodeInfo.IsInMask2D, nodeInfo.HierarychyOrder );
                }
            }
            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    children[i].UpdataInfo();
                }
            }
        }

        public List<KeyValuePair<UIDCTreeNode, UINodeInfo>> GetNodesInfo()
        {
            List<KeyValuePair<UIDCTreeNode, UINodeInfo>> list = new List<KeyValuePair<UIDCTreeNode, UINodeInfo>>();
            list.Add(new KeyValuePair<UIDCTreeNode, UINodeInfo>(this, nodeInfo));

            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    List<KeyValuePair<UIDCTreeNode, UINodeInfo>> childList = children[i].GetNodesInfo();
                    if (childList.Count > 0)
                    {
                        if (nodeInfo.IsInMask == 0)
                        {
                            for (int j = 0; j < childList.Count; ++j)
                            {
                                childList[j].Value.IsInMask = 1;
                            }
                        }
                        else if (nodeInfo.IsInMask2D != -1)
                        {
                            for (int j = 0; j < childList.Count; ++j)
                            {
                                if (childList[j].Value.IsInMask2D == -1)
                                {
                                    childList[j].Value.IsInMask2D = nodeInfo.IsInMask2D;
                                    childList[j].Value.Clip(nodeInfo.GetRect());
                                }
                            }
                        }
                        list.AddRange(childList);
                    }
                }
            }
            nodeInfo.IsInMask2D = -1;
            return list;
        }

        public void AddChild(UIDCTreeNode node)
        {
            if (node == null)
            {
                return;
            }

            if (node == this)
            {
                return;
            }

            if (node.isDestroy)
            {
                return;
            }

            if (node.parent == this)
            {
                return;
            }

            node.SetParent(null);
            children.Add(node);
            node.parent = this;
            node.SetPositionX(position.x + marginX);
            node.Depth = depth + 1;
        }

        private void RemoveChild(UIDCTreeNode node)
        {
            if (node == null)
            {
                return;
            }

            int index = -1;
            for (int i = 0; i < children.Count; i++)
            {
                if (node == children[i])
                {
                    index = i;
                    break;
                }
            }

            if (index != -1)
            {
                children[index].parent = null;
                children.RemoveAt(index);
            }
        }

        private void SetParent(UIDCTreeNode node)
        {
            if (node == null)
            {
                if (parent != null)
                {
                    parent.RemoveChild(this);
                    parent = null;
                }
                return;
            }

            if (node == this)
            {
                return;
            }

            if (node.isDestroy)
            {
                return;
            }

            if (node != parent)
            {
                if (parent != null)
                {
                    parent.RemoveChild(this);
                    parent = null;
                }
                node.AddChild(this);
            }
        }

        private void SetSubTitle(string subTitle, Color titleColor)
        {
            this.subTitle = subTitle;

            if (subTitle != null)
            {
                if (subTitleGuiStyle == null)
                {
                    subTitleGuiStyle = new GUIStyle();
                    subTitleGuiStyle.fontSize = 11;
                    subTitleGuiStyle.alignment = TextAnchor.MiddleLeft;
                }
                subTitleGuiStyle.normal.textColor = titleColor;
            }
        }

        //calculate node size
        private void CalcRecursiveSize()
        {
            recursiveSize.x = position.width;
            recursiveSize.y = position.height;

            if (isShow)
            {
                float childMaxWidth = 0f;
                for (int i = 0; i < children.Count; i++)
                {
                    if (children[i] != null)
                    {
                        childMaxWidth = Math.Max(childMaxWidth, children[i].recursiveSize.x);
                        recursiveSize.y = recursiveSize.y + children[i].recursiveSize.y;
                    }
                }

                //all nodes have same size
                if (childMaxWidth > 0f)
                {
                    recursiveSize.x = childMaxWidth + Math.Abs(marginX);
                }
            }
        }

        private void SetPositionX(float x)
        {
            position.x = x;
            for (int i = 0; i < children.Count; i++)
            {
                if (children[i] != null)
                {
                    children[i].SetPositionX(position.x + marginX);
                }
            }
        }

        private bool IsShowRecursively()
        {
            if (!isShow)
            {
                return false;
            }

            if (parent == null)
            {
                return isShow;
            }

            return parent.IsShowRecursively();
        }

        private void GenInfo()
        {
            rectTransform = assetObject.GetComponent<RectTransform>();
            MaskableGraphic maskableGraphic = assetObject.GetComponent<MaskableGraphic>();
            nodeInfo = new UINodeInfo(maskableGraphic != null, assetObject.GetComponent<Canvas>() != null, assetObject.name);
            nodeInfo.Depth = depth;

            Mask mask = assetObject.GetComponent<Mask>();
            if(mask != null && mask.enabled == true)
            {
                nodeInfo.IsInMask = 0;
            }else
            {
                nodeInfo.IsInMask = -1;
            }
            RectMask2D rectMask2D = assetObject.GetComponent<RectMask2D>();
            if (rectMask2D != null && rectMask2D.enabled == true)
            {
                nodeInfo.IsInMask2D = nodeInfo.GetHashCode();
            }
            else
            {
                nodeInfo.IsInMask2D = -1;
            }
            
            if (maskableGraphic != null)
            {
                if(maskableGraphic.materialForRendering != null)
                {
                    nodeInfo.MaterialInstanceID = maskableGraphic.materialForRendering.GetInstanceID();
                    nodeInfo.TextureID = maskableGraphic.mainTexture.GetInstanceID();
                }else
                {
                    Debug.LogError("null materialForRendering: " + assetObject.name);
                }
               
            }
            Matrix4x4 localToWorldMatrix = assetObject.transform.localToWorldMatrix;
            Text t = assetObject.GetComponent<Text>();
            if (t != null)
            {
                if (t.text.Equals(""))
                {
                    for (int i = 0; i < 4; i++)
                    {
                        nodeInfo.Corners[i] = localToWorldMatrix.MultiplyPoint(Vector2.zero);
                    }
                }
                else
                {
                    Rect rect = t.GetPixelAdjustedRect();
                    float halfWidth = t.preferredWidth / 2;
                    float halfHeight = t.preferredHeight / 2;
                    Vector2 pos_1 = Vector2.zero;
                    int idx = (int)t.alignment;
                    if (idx % 3 == 0)
                    {
                        pos_1.x = -rect.width / 2 + halfWidth;
                    }
                    else if (idx % 3 == 2)
                    {
                        pos_1.x = rect.width / 2 - halfWidth;
                    }
                    if (idx / 3 == 0)
                    {
                        pos_1.y = rect.height / 2 - halfHeight;
                    }
                    else if (idx / 3 == 2)
                    {
                        pos_1.y = -rect.height / 2 + halfHeight;
                    }
                    Vector2[] pos = new Vector2[4];
                    pos[0] = new Vector2(pos_1.x - halfWidth, pos_1.y - halfHeight);
                    pos[1] = new Vector2(pos_1.x - halfWidth, pos_1.y + halfHeight);
                    pos[2] = new Vector2(pos_1.x + halfWidth, pos_1.y + halfHeight);
                    pos[3] = new Vector2(pos_1.x + halfWidth, pos_1.y - halfHeight);

                    if (rectTransform.pivot.x < 0.000001)
                    {
                        for (int i = 0; i < 4; ++i)
                        {
                            pos[i] = new Vector2(pos[i].x + rect.size.x / 2, pos[i].y);
                        }
                    }
                    else if (Mathf.Abs(rectTransform.pivot.x - 1) < 0.000001)
                    {
                        for (int i = 0; i < 4; ++i)
                        {
                            pos[i] = new Vector2(pos[i].x - rect.size.x / 2, pos[i].y);
                        }
                    }

                    if (rectTransform.pivot.y < 0.000001)
                    {
                        for (int i = 0; i < 4; ++i)
                        {
                            pos[i] = new Vector2(pos[i].x, pos[i].y + rect.size.y / 2);
                        }
                    }
                    else if (Mathf.Abs(rectTransform.pivot.y - 1) < 0.000001)
                    {
                        for (int i = 0; i < 4; ++i)
                        {
                            pos[i] = new Vector2(pos[i].x, pos[i].y - rect.size.y / 2);
                        }
                    }

                    for (int i = 0; i < 4; i++)
                    {
                        nodeInfo.Corners[i] = localToWorldMatrix.MultiplyPoint(pos[i]);
                    }
                }
            }
            else
            {
                if(rectTransform != null)//有可能谁整一个Transform
                {
                    rectTransform.GetWorldCorners(nodeInfo.Corners);
                }else
                {
                    Debug.LogError("null RectTransform: " + assetObject.name);
                }
               
            }
        }
    }
}
